package br.com.abril.sforce;

import java.io.IOException;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.annotation.JsonIgnore;

import br.com.abril.profile.Preference;
import br.com.abril.profile.PreferenceType;
import br.com.abril.profile.Preferences;

public class ProxyProvider extends ProxySelector {
	
	private Logger logger = Logger.getLogger( this.getClass() );
	
	private Proxy proxy;
	private List<Proxy> proxies;
	private Preferences preferences;
	
	private ProxyEntry proxyEntry;
	
	private String host;
	private String user;
	private String password;
	
	private Boolean enabled;
	
	public ProxyProvider() {
		enabled = false;
		proxies = new ArrayList<Proxy>();
		proxyEntry = new ProxyEntry();
	}
	
	public ProxyProvider(Preferences preferences) {
		this();
		this.preferences = preferences;
		init ();
		
	}
	
	public void loadProxyFromPreferences() {
        this.proxyEntry.setEnabled(preferences.getBooleanValue( PreferenceType.USE_PROXY ));
        this.proxyEntry.setHost(preferences.getValue(PreferenceType.PROXY_HOST));
        this.proxyEntry.setPort(preferences.getValue(PreferenceType.PROXY_PORT));
        this.proxyEntry.setUser(preferences.getValue(PreferenceType.PROXY_USER));
        this.proxyEntry.setPassword(preferences.getValue(PreferenceType.PROXY_PASSWORD));
	}
	
	
	public void setProxyPreferences ( ProxyEntry proxyEntry ) {
		
		Preference useProxy = preferences.get(PreferenceType.USE_PROXY);
		useProxy.setValue(proxyEntry.getEnabled().toString());

		Preference host = preferences.get(PreferenceType.PROXY_HOST);
		host.setValue(proxyEntry.getHost());

		Preference port = preferences.get(PreferenceType.PROXY_PORT);
		port.setValue(proxyEntry.getPort());

		Preference user = preferences.get(PreferenceType.PROXY_USER);
		user.setValue(proxyEntry.getUser());
		
		Preference password = preferences.get(PreferenceType.PROXY_PASSWORD);
		password.setValue(proxyEntry.getPassword());
		
	}
	
	public void setUpProxy() {
	
        if (! this.proxyEntry.getEnabled() )  {
            return;
        }		
        
        this.proxies = new ArrayList<Proxy>();
        
        SocketAddress addr = new InetSocketAddress( this.proxyEntry.getHost() 
				  ,this.proxyEntry.getIntPort() );

        this.proxy = new Proxy(Proxy.Type.HTTP, addr);
        
        Authenticator ath = new Authenticator() {
        		@Override	
        		protected PasswordAuthentication getPasswordAuthentication() {
        				return new PasswordAuthentication( proxyEntry.getUser()
        							                    ,  proxyEntry.getPassword().toCharArray() );
        		}
        };
        
        Authenticator.setDefault(ath);
        
        proxies.add(proxy);
		
        setUpProxySystemProperties();
        
        
        
	}
	
	private void setUpProxySystemProperties() {
		
        System.setProperty("https.proxyHost", this.proxyEntry.getHost());
        System.setProperty("https.proxyPort", this.proxyEntry.getPort());
        System.setProperty("https.proxyUser", this.proxyEntry.getUser());
        System.setProperty("https.proxyPassword", this.proxyEntry.getPassword());

        System.setProperty("proxyHost", this.proxyEntry.getHost());
        System.setProperty("proxyPort", this.proxyEntry.getPort());
        System.setProperty("proxyUser", this.proxyEntry.getUser());
        System.setProperty("proxyPassword", this.proxyEntry.getPassword());
		
	}
	
	public void init () {
		
		loadProxyFromPreferences();
		
		setUpProxy();
		
 	}
	
	@Override
	public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
		logger.error( "Unable to connect to " + uri , ioe);
	}

	@Override
	public List<Proxy> select(URI uri) {
		return proxies;
	}
	
	@JsonIgnore
	public List<Proxy> getProxies() {
		return proxies;
	}
	
	public Proxy getProxy() {
		return proxy;
	}
	
	public Boolean isEnabled() {
		return this.proxyEntry.getEnabled();
	}

	public ProxyEntry getProxyEntry() {
		return proxyEntry;
	}
	
	public void setProxyEntry(ProxyEntry proxyEntry) {
		this.proxyEntry = proxyEntry;
	}
	
	public void setProxies(List<Proxy> proxies) {
		this.proxies = proxies;
	}
	

	
}
